home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 July: Mac OS SDK / Dev.CD Jul 99 SDK1.toast / Development Kits / Mac OS / OpenGL 1.0 SDK / Source / Libraries / tk / tkshapes.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-05-18  |  25.9 KB  |  1,070 lines  |  [TEXT/CWIE]

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <math.h>
  4.  
  5. #include "gl.h"
  6. #include "glu.h"
  7. #include "3d.h"
  8. #include "tk.h"
  9.  
  10. #define SPHEREWIRE        0
  11. #define CUBEWIRE           1
  12. #define BOXWIRE            2
  13. #define TORUSWIRE           3
  14. #define CYLINDERWIRE        4
  15. #define ICOSAWIRE           5
  16. #define OCTAWIRE           6
  17. #define TETRAWIRE           7
  18. #define DODECAWIRE        8
  19. #define CONEWIRE           9
  20.  
  21. #define SPHERESOLID       10
  22. #define CUBESOLID          11
  23. #define BOXSOLID          12
  24. #define TORUSSOLID       13
  25. #define CYLINDERSOLID    14
  26. #define ICOSASOLID       15
  27. #define OCTASOLID          16
  28. #define TETRASOLID       17
  29. #define DODECASOLID       18
  30. #define CONESOLID          19
  31.  
  32. #define PI 3.1415926535897
  33.  
  34. /*    structure for each geometric object    */
  35. typedef struct model {
  36.     GLuint list;          /*  display list to render object   */
  37.     struct model *ptr;    /*  pointer to next object    */
  38.     int numParam;          /*  # of parameters        */
  39.     GLdouble *params;       /*  array with parameters    */
  40. } MODEL, *MODELPTR;
  41.  
  42. /*    array of linked lists--used to keep track of display lists 
  43.  *    for each different type of geometric object.
  44.  */
  45. static MODELPTR lists[25] = {
  46.     NULL, NULL, NULL, NULL, NULL,
  47.     NULL, NULL, NULL, NULL, NULL,
  48.     NULL, NULL, NULL, NULL, NULL,
  49.     NULL, NULL, NULL, NULL, NULL,
  50.     NULL, NULL, NULL, NULL, NULL
  51. };
  52.  
  53. static GLuint findList(int lindex, GLdouble *paramArray, int size);
  54. static int compareParams(GLdouble *oneArray, GLdouble *twoArray, int size);
  55. static GLuint makeModelPtr(int lindex, int list, GLdouble *sizeArray, int count);
  56.  
  57. static void drawbox(GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLenum);
  58. static void doughnut(GLdouble, GLdouble, GLint, GLint, GLenum);
  59. static void icosahedron(GLdouble *, GLdouble, GLenum);
  60. static void octahedron(GLdouble *, GLdouble, GLenum);
  61. static void tetrahedron(GLdouble *, GLdouble, GLenum);
  62. static void subdivide(int, GLdouble *, GLdouble *, GLdouble *, GLdouble *, GLdouble, GLenum, int);
  63. static void drawtriangle(int, int, int, GLdouble *, GLdouble, GLenum, int);
  64. static void recorditem(GLdouble *, GLdouble *, GLdouble *, GLdouble *, GLdouble, GLenum, int);
  65. static void initdodec(void);
  66. static void dodecahedron(GLdouble *, GLdouble, GLenum);
  67. static void pentagon(int, int, int, int, int, GLenum);
  68.  
  69.  
  70. /*  Render wire frame or solid sphere.  If no display list with
  71.  *  the current model size exists, create a new display list.
  72.  */
  73. void tkWireSphere(GLuint list, GLdouble radius)
  74. {
  75.     GLUquadricObj *quadObj;
  76.     GLdouble *sizeArray;
  77.     GLuint displayList;
  78.  
  79.     sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 1);
  80.     *sizeArray = radius;
  81.     displayList = findList(SPHEREWIRE, sizeArray, 1);
  82.  
  83.     if(displayList == 0)
  84.     {
  85.         glNewList(makeModelPtr(SPHEREWIRE, list, sizeArray, 1),
  86.             GL_COMPILE_AND_EXECUTE);
  87.             quadObj = gluNewQuadric();
  88.             gluQuadricDrawStyle(quadObj, GLU_LINE);
  89.             gluSphere(quadObj, radius, 32, 32);
  90.         glEndList();
  91.     }
  92.     else
  93.     {
  94.         glCallList(displayList);
  95.         free(sizeArray);
  96.     }
  97. }
  98.  
  99. void tkSolidSphere(GLuint list, GLdouble radius)
  100. {
  101.     GLUquadricObj *quadObj;
  102.     GLdouble *sizeArray;
  103.     GLuint displayList;
  104.  
  105.     sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 1);
  106.     *sizeArray = radius;
  107.     displayList = findList(SPHERESOLID, sizeArray, 1);
  108.  
  109.     if(displayList == 0) {
  110.     glNewList(makeModelPtr(SPHERESOLID, list, sizeArray, 1),
  111.         GL_COMPILE_AND_EXECUTE);
  112.         quadObj = gluNewQuadric();
  113.         gluQuadricDrawStyle(quadObj, GLU_FILL);
  114.         gluQuadricNormals(quadObj, GLU_SMOOTH);
  115.         gluSphere(quadObj, radius, 32, 32);
  116.     glEndList();
  117.     }
  118.     else {
  119.     glCallList(displayList);
  120.     free(sizeArray);
  121.     }
  122. }
  123.  
  124. /*  Render wire frame or solid cube.  If no display list with
  125.  *  the current model size exists, create a new display list.
  126.  */
  127. void tkWireCube(GLuint list, GLdouble size)
  128. {
  129.     GLdouble *sizeArray;
  130.     GLuint displayList;
  131.  
  132.     sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 1);
  133.     *sizeArray = size;
  134.     displayList = findList(CUBEWIRE, sizeArray, 1);
  135.  
  136.     if(displayList == 0) {
  137.     glNewList(makeModelPtr(CUBEWIRE, list, sizeArray, 1),
  138.         GL_COMPILE_AND_EXECUTE);
  139.         drawbox(-size/2., size/2., -size/2., size/2., 
  140.         -size/2., size/2., GL_LINE_LOOP);
  141.     glEndList();
  142.     }
  143.     else {
  144.     glCallList(displayList);
  145.     free(sizeArray);
  146.     }
  147. }
  148.  
  149. void tkSolidCube(GLuint list, GLdouble size)
  150. {
  151.     GLdouble *sizeArray;
  152.     GLuint displayList;
  153.  
  154.     sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 1);
  155.     *sizeArray = size;
  156.     displayList = findList(CUBESOLID, sizeArray, 1);
  157.  
  158.     if(displayList == 0) {
  159.     glNewList(makeModelPtr(CUBESOLID, list, sizeArray, 1),
  160.         GL_COMPILE_AND_EXECUTE);
  161.         drawbox(-size/2., size/2., -size/2., size/2., 
  162.         -size/2., size/2., GL_QUADS);
  163.     glEndList();
  164.     }
  165.     else {
  166.     glCallList(displayList);
  167.     free(sizeArray);
  168.     }
  169. }
  170.  
  171. /*  Render wire frame or solid cube.  If no display list with
  172.  *  the current model size exists, create a new display list.
  173.  */
  174. void tkWireBox(GLuint list, GLdouble width, GLdouble height, GLdouble depth)
  175. {
  176.     GLdouble *sizeArray, *tmp;
  177.     GLuint displayList;
  178.  
  179.     sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 3);
  180.     tmp = sizeArray;
  181.     *tmp++ = width;
  182.     *tmp++ = height;
  183.     *tmp++ = depth;
  184.     displayList = findList(BOXWIRE, sizeArray, 3);
  185.  
  186.     if(displayList == 0) {
  187.     glNewList(makeModelPtr(BOXWIRE, list, sizeArray, 3),
  188.         GL_COMPILE_AND_EXECUTE);
  189.         drawbox(-width/2., width/2., -height/2., height/2., 
  190.         -depth/2., depth/2., GL_LINE_LOOP);
  191.     glEndList();
  192.     }
  193.     else {
  194.     glCallList(displayList);
  195.     free(sizeArray);
  196.     }
  197. }
  198.  
  199. void tkSolidBox(GLuint list, GLdouble width, GLdouble height, GLdouble depth)
  200. {
  201.     GLdouble *sizeArray, *tmp;
  202.     GLuint displayList;
  203.  
  204.     sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 3);
  205.     tmp = sizeArray;
  206.     *tmp++ = width;
  207.     *tmp++ = height;
  208.     *tmp++ = depth;
  209.     displayList = findList(BOXSOLID, sizeArray, 3);
  210.  
  211.     if(displayList == 0) {
  212.     glNewList(makeModelPtr(BOXSOLID, list, sizeArray, 3),
  213.         GL_COMPILE_AND_EXECUTE);
  214.         drawbox(-width/2., width/2., -height/2., height/2., 
  215.         -depth/2., depth/2., GL_QUADS);
  216.     glEndList();
  217.     }
  218.     else {
  219.     glCallList(displayList);
  220.     free(sizeArray);
  221.     }
  222. }
  223.  
  224. /*  Render wire frame or solid tori.  If no display list with
  225.  *  the current model size exists, create a new display list.
  226.  */
  227. void tkWireTorus(GLuint list, GLdouble innerRadius, GLdouble outerRadius)
  228. {
  229.     GLdouble *sizeArray, *tmp;
  230.     GLuint displayList;
  231.  
  232.     sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 2);
  233.     tmp = sizeArray;
  234.     *tmp++ = innerRadius;
  235.     *tmp++ = outerRadius;
  236.     displayList = findList(TORUSWIRE, sizeArray, 2);
  237.  
  238.     if(displayList == 0) {
  239.     glNewList(makeModelPtr(TORUSWIRE, list, sizeArray, 2),
  240.         GL_COMPILE_AND_EXECUTE);
  241.         doughnut(innerRadius, outerRadius, 10, 20, GL_LINE_LOOP);
  242.     glEndList();
  243.     }
  244.     else {
  245.     glCallList(displayList);
  246.     free(sizeArray);
  247.     }
  248. }
  249.  
  250. void tkSolidTorus(GLuint list, GLdouble innerRadius, GLdouble outerRadius)
  251. {
  252.     GLdouble *sizeArray, *tmp;
  253.     GLuint displayList;
  254.  
  255.     sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 2);
  256.     tmp = sizeArray;
  257.     *tmp++ = innerRadius;
  258.     *tmp++ = outerRadius;
  259.     displayList = findList(TORUSSOLID, sizeArray, 2);
  260.  
  261.     if(displayList == 0) {
  262.     glNewList(makeModelPtr(TORUSSOLID, list, sizeArray, 2),
  263.         GL_COMPILE_AND_EXECUTE);
  264.         doughnut(innerRadius, outerRadius, 16, 30, GL_QUADS);
  265.     glEndList();
  266.     }
  267.     else {
  268.     glCallList(displayList);
  269.     free(sizeArray);
  270.     }
  271. }
  272.  
  273. /*  Render wire frame or solid cylinders.  If no display list with
  274.  *  the current model size exists, create a new display list.
  275.  */
  276. void tkWireCylinder(GLuint list, GLdouble radius, GLdouble height)
  277. {
  278.     GLUquadricObj *quadObj;
  279.     GLdouble *sizeArray, *tmp;
  280.     GLuint displayList;
  281.  
  282.     sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 2);
  283.     tmp = sizeArray;
  284.     *tmp++ = radius;
  285.     *tmp++ = height;
  286.     displayList = findList(CYLINDERWIRE, sizeArray, 2);
  287.  
  288.     if(displayList == 0) {
  289.     glNewList(makeModelPtr(CYLINDERWIRE, list, sizeArray, 2),
  290.         GL_COMPILE_AND_EXECUTE);
  291.         glPushMatrix();
  292.         glRotatef(90.0, 1.0, 0.0, 0.0);
  293.         glTranslatef(0.0, 0.0, -1.0);
  294.         quadObj = gluNewQuadric();
  295.         gluQuadricDrawStyle(quadObj, GLU_LINE);
  296.         gluCylinder(quadObj, radius, radius, height, 24, 4);
  297.         glPopMatrix();
  298.     glEndList();
  299.     }
  300.     else {
  301.     glCallList(displayList);
  302.     free(sizeArray);
  303.     }
  304. }
  305.  
  306. void tkSolidCylinder(GLuint list, GLdouble radius, GLdouble height)
  307. {
  308.     GLUquadricObj *quadObj;
  309.     GLdouble *sizeArray, *tmp;
  310.     GLuint displayList;
  311.  
  312.     sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 2);
  313.     tmp = sizeArray;
  314.     *tmp++ = radius;
  315.     *tmp++ = height;
  316.     displayList = findList(CYLINDERSOLID, sizeArray, 2);
  317.  
  318.     if(displayList == 0) {
  319.     glNewList(makeModelPtr(CYLINDERSOLID, list, sizeArray, 2),
  320.         GL_COMPILE_AND_EXECUTE);
  321.         glPushMatrix();
  322.         glRotatef(90.0, 1.0, 0.0, 0.0);
  323.         glTranslatef(0.0, 0.0, -1.0);
  324.         quadObj = gluNewQuadric();
  325.         gluQuadricDrawStyle(quadObj, GLU_FILL);
  326.         gluQuadricNormals(quadObj, GLU_SMOOTH);
  327.         gluCylinder(quadObj, radius, radius, height, 24, 4);
  328.         glPopMatrix();
  329.     glEndList();
  330.     }
  331.     else {
  332.     glCallList(displayList);
  333.     free(sizeArray);
  334.     }
  335. }
  336.  
  337. /*  Render wire frame or solid icosahedra.  If no display list with
  338.  *  the current model size exists, create a new display list.
  339.  */
  340. void tkWireIcosahedron(GLuint list, GLdouble radius)
  341. {
  342.     GLdouble *sizeArray;
  343.     GLuint displayList;
  344.     GLdouble center[3] = {0.0, 0.0, 0.0};
  345.  
  346.     sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 1);
  347.     *sizeArray = radius;
  348.     displayList = findList(ICOSAWIRE, sizeArray, 1);
  349.  
  350.     if(displayList == 0) {
  351.     glNewList(makeModelPtr(ICOSAWIRE, list, sizeArray, 1),
  352.         GL_COMPILE_AND_EXECUTE);
  353.         icosahedron(center, radius, GL_LINE_LOOP);
  354.     glEndList();
  355.     }
  356.     else {
  357.     glCallList(displayList);
  358.     free(sizeArray);
  359.     }
  360. }
  361.  
  362. void tkSolidIcosahedron(GLuint list, GLdouble radius)
  363. {
  364.     GLdouble *sizeArray;
  365.     GLuint displayList;
  366.     GLdouble center[3] = {0.0, 0.0, 0.0};
  367.  
  368.     sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 1);
  369.     *sizeArray = radius;
  370.     displayList = findList(ICOSASOLID, sizeArray, 1);
  371.  
  372.     if(displayList == 0) {
  373.     glNewList(makeModelPtr(ICOSASOLID, list, sizeArray, 1),
  374.         GL_COMPILE_AND_EXECUTE);
  375.         icosahedron(center, radius, GL_TRIANGLES);
  376.     glEndList();
  377.     }
  378.     else {
  379.     glCallList(displayList);
  380.     free(sizeArray);
  381.     }
  382. }
  383.  
  384. /*  Render wire frame or solid octahedra.  If no display list with
  385.  *  the current model size exists, create a new display list.
  386.  */
  387. void tkWireOctahedron(GLuint list, GLdouble radius)
  388. {
  389.     GLdouble *sizeArray;
  390.     GLuint displayList;
  391.     GLdouble center[3] = {0.0, 0.0, 0.0};
  392.  
  393.     sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 1);
  394.     *sizeArray = radius;
  395.     displayList = findList(OCTAWIRE, sizeArray, 1);
  396.  
  397.     if(displayList == 0) {
  398.     glNewList(makeModelPtr(OCTAWIRE, list, sizeArray, 1),
  399.         GL_COMPILE_AND_EXECUTE);
  400.         octahedron(center, radius, GL_LINE_LOOP);
  401.     glEndList();
  402.     }
  403.     else {
  404.     glCallList(displayList);
  405.     free(sizeArray);
  406.     }
  407. }
  408.  
  409. void tkSolidOctahedron(GLuint list, GLdouble radius)
  410. {
  411.     GLdouble *sizeArray;
  412.     GLuint displayList;
  413.     GLdouble center[3] = {0.0, 0.0, 0.0};
  414.  
  415.     sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 1);
  416.     *sizeArray = radius;
  417.     displayList = findList(OCTASOLID, sizeArray, 1);
  418.  
  419.     if(displayList == 0) {
  420.     glNewList(makeModelPtr(OCTASOLID, list, sizeArray, 1),
  421.         GL_COMPILE_AND_EXECUTE);
  422.         octahedron(center, radius, GL_TRIANGLES);
  423.     glEndList();
  424.     }
  425.     else {
  426.     glCallList(displayList);
  427.     free(sizeArray);
  428.     }
  429. }
  430.  
  431. /*  Render wire frame or solid tetrahedra.  If no display list with
  432.  *  the current model size exists, create a new display list.
  433.  */
  434. void tkWireTetrahedron(GLuint list, GLdouble radius)
  435. {
  436.     GLdouble *sizeArray;
  437.     GLuint displayList;
  438.     GLdouble center[3] = {0.0, 0.0, 0.0};
  439.  
  440.     sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 1);
  441.     *sizeArray = radius;
  442.     displayList = findList(TETRAWIRE, sizeArray, 1);
  443.  
  444.     if(displayList == 0) {
  445.     glNewList(makeModelPtr(TETRAWIRE, list, sizeArray, 1),
  446.         GL_COMPILE_AND_EXECUTE);
  447.         tetrahedron(center, radius, GL_LINE_LOOP);
  448.     glEndList();
  449.     }
  450.     else {
  451.     glCallList(displayList);
  452.     free(sizeArray);
  453.     }
  454. }
  455.  
  456. void tkSolidTetrahedron(GLuint list, GLdouble radius)
  457. {
  458.     GLdouble *sizeArray;
  459.     GLuint displayList;
  460.     GLdouble center[3] = {0.0, 0.0, 0.0};
  461.  
  462.     sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 1);
  463.     *sizeArray = radius;
  464.     displayList = findList(TETRASOLID, sizeArray, 1);
  465.  
  466.     if(displayList == 0) {
  467.     glNewList(makeModelPtr(TETRASOLID, list, sizeArray, 1),
  468.         GL_COMPILE_AND_EXECUTE);
  469.         tetrahedron(center, radius, GL_TRIANGLES);
  470.     glEndList();
  471.     }
  472.     else {
  473.     glCallList(displayList);
  474.     free(sizeArray);
  475.     }
  476. }
  477.  
  478. /*  Render wire frame or solid dodecahedra.  If no display list with
  479.  *  the current model size exists, create a new display list.
  480.  */
  481. void tkWireDodecahedron(GLuint list, GLdouble radius)
  482. {
  483.     GLdouble *sizeArray;
  484.     GLuint displayList;
  485.     GLdouble center[3] = {0.0, 0.0, 0.0};
  486.  
  487.     sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 1);
  488.     *sizeArray = radius;
  489.     displayList = findList(DODECAWIRE, sizeArray, 1);
  490.  
  491.     if(displayList == 0) {
  492.     glNewList(makeModelPtr(DODECAWIRE, list, sizeArray, 1),
  493.         GL_COMPILE_AND_EXECUTE);
  494.         dodecahedron(center, radius/1.73, GL_LINE_LOOP);
  495.     glEndList();
  496.     }
  497.     else {
  498.     glCallList(displayList);
  499.     free(sizeArray);
  500.     }
  501. }
  502.  
  503. void tkSolidDodecahedron(GLuint list, GLdouble radius)
  504. {
  505.     GLdouble *sizeArray;
  506.     GLuint displayList;
  507.     GLdouble center[3] = {0.0, 0.0, 0.0};
  508.  
  509.     sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 1);
  510.     *sizeArray = radius;
  511.     displayList = findList(DODECASOLID, sizeArray, 1);
  512.  
  513.     if(displayList == 0) {
  514.     glNewList(makeModelPtr(DODECASOLID, list, sizeArray, 1),
  515.         GL_COMPILE_AND_EXECUTE);
  516.         dodecahedron(center, radius/1.73, GL_TRIANGLE_FAN);
  517.     glEndList();
  518.     }
  519.     else {
  520.     glCallList(displayList);
  521.     free(sizeArray);
  522.     }
  523. }
  524.  
  525. /*  Render wire frame or solid cones.  If no display list with
  526.  *  the current model size exists, create a new display list.
  527.  */
  528. void tkWireCone(GLuint list, GLdouble base, GLdouble height)
  529. {
  530.     GLUquadricObj *quadObj;
  531.     GLdouble *sizeArray, *tmp;
  532.     GLuint displayList;
  533.  
  534.     sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 2);
  535.     tmp = sizeArray;
  536.     *tmp++ = base;
  537.     *tmp++ = height;
  538.     displayList = findList(CONEWIRE, sizeArray, 2);
  539.  
  540.     if(displayList == 0) {
  541.     glNewList(makeModelPtr(CONEWIRE, list, sizeArray, 2),
  542.         GL_COMPILE_AND_EXECUTE);
  543.         quadObj = gluNewQuadric();
  544.         gluQuadricDrawStyle(quadObj, GLU_LINE);
  545.         gluCylinder(quadObj, base, 0.0, height, 30, 20);
  546.     glEndList();
  547.     }
  548.     else {
  549.     glCallList(displayList);
  550.     free(sizeArray);
  551.     }
  552. }
  553.  
  554. void tkSolidCone(GLuint list, GLdouble base, GLdouble height)
  555. {
  556.     GLUquadricObj *quadObj;
  557.     GLdouble *sizeArray, *tmp;
  558.     GLuint displayList;
  559.  
  560.     sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 2);
  561.     tmp = sizeArray;
  562.     *tmp++ = base;
  563.     *tmp++ = height;
  564.     displayList = findList(CONESOLID, sizeArray, 2);
  565.  
  566.     if(displayList == 0) {
  567.     glNewList(makeModelPtr(CONESOLID, list, sizeArray, 2),
  568.         GL_COMPILE_AND_EXECUTE);
  569.         quadObj = gluNewQuadric();
  570.         gluQuadricDrawStyle(quadObj, GLU_FILL);
  571.         gluQuadricNormals(quadObj, GLU_SMOOTH);
  572.         gluCylinder(quadObj, base, 0.0, height, 30, 20);
  573.     glEndList();
  574.     }
  575.     else {
  576.     glCallList(displayList);
  577.     free(sizeArray);
  578.     }
  579. }
  580.  
  581. /* Routines to build 3 dimensional solids, including:
  582.  *
  583.  * drawbox, doughnut, icosahedron, 
  584.  * octahedron, tetrahedron, dodecahedron.
  585.  */
  586.  
  587. /* drawbox:
  588.  *
  589.  * draws a rectangular box with the given x, y, and z ranges.  
  590.  * The box is axis-aligned.
  591.  */
  592. static void drawbox(GLdouble x0, GLdouble x1, GLdouble y0, GLdouble y1,
  593.     GLdouble z0, GLdouble z1, GLenum type)
  594. {
  595.     static GLdouble n[6][3] = {
  596.     {-1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 0.0, 0.0},
  597.     {0.0, -1.0, 0.0}, {0.0, 0.0, 1.0}, {0.0, 0.0, -1.0}
  598.     };
  599.     static GLint faces[6][4] = {
  600.     { 0, 1, 2, 3 }, { 3, 2, 6, 7 }, { 7, 6, 5, 4 },
  601.     { 4, 5, 1, 0 }, { 5, 6, 2, 1 }, { 7, 4, 0, 3 }
  602.     };
  603.     GLdouble v[8][3], tmp;
  604.     GLint i;
  605.  
  606.     if(x0 > x1) {
  607.     tmp = x0; x0 = x1; x1 = tmp;
  608.     }
  609.     if(y0 > y1) {
  610.     tmp = y0; y0 = y1; y1 = tmp; 
  611.     }
  612.     if(z0 > z1) {
  613.     tmp = z0; z0 = z1; z1 = tmp; 
  614.     }
  615.     v[0][0] = v[1][0] = v[2][0] = v[3][0] = x0;
  616.     v[4][0] = v[5][0] = v[6][0] = v[7][0] = x1;
  617.     v[0][1] = v[1][1] = v[4][1] = v[5][1] = y0;
  618.     v[2][1] = v[3][1] = v[6][1] = v[7][1] = y1;
  619.     v[0][2] = v[3][2] = v[4][2] = v[7][2] = z0;
  620.     v[1][2] = v[2][2] = v[5][2] = v[6][2] = z1;
  621.  
  622.     for(i = 0; i < 6; i++) {
  623.     glBegin(type);
  624.     glNormal3dv(&n[i][0]);
  625.     glVertex3dv(&v[faces[i][0]][0]);
  626.     glNormal3dv(&n[i][0]);
  627.     glVertex3dv(&v[faces[i][1]][0]);
  628.     glNormal3dv(&n[i][0]);
  629.     glVertex3dv(&v[faces[i][2]][0]);
  630.     glNormal3dv(&n[i][0]);
  631.     glVertex3dv(&v[faces[i][3]][0]);
  632.     glEnd();
  633.     }
  634. }
  635.  
  636. /* doughnut:
  637.  *
  638.  * draws a doughnut, centered at(0, 0, 0) whose axis is aligned with
  639.  * the z-axis.  The doughnut's major radius is R, and minor radius is r.
  640.  */
  641.  
  642. static void doughnut(GLdouble r, GLdouble R, GLint nsides, GLint rings, GLenum type)
  643. {
  644.     int    i, j;
  645.     GLdouble    theta, phi, theta1, phi1;
  646.     GLdouble    p0[03], p1[3], p2[3], p3[3];
  647.     GLdouble    n0[3], n1[3], n2[3], n3[3];
  648.  
  649.     for(i = 0; i < rings; i++) {
  650.     theta = (GLdouble)i*2.0*PI/rings;
  651.     theta1 = (GLdouble)(i+1)*2.0*PI/rings;
  652.     for(j = 0; j < nsides; j++) {
  653.         phi = (GLdouble)j*2.0*PI/nsides;
  654.         phi1 = (GLdouble)(j+1)*2.0*PI/nsides;
  655.  
  656.         p0[0] = cos(theta)*(R + r*cos(phi));
  657.         p0[1] = -sin(theta)*(R + r*cos(phi));
  658.         p0[2] = r*sin(phi);
  659.  
  660.         p1[0] = cos(theta1)*(R + r*cos(phi));
  661.         p1[1] = -sin(theta1)*(R + r*cos(phi));
  662.         p1[2] = r*sin(phi);
  663.  
  664.         p2[0] = cos(theta1)*(R + r*cos(phi1));
  665.         p2[1] = -sin(theta1)*(R + r*cos(phi1));
  666.         p2[2] = r*sin(phi1);
  667.  
  668.         p3[0] = cos(theta)*(R + r*cos(phi1));
  669.         p3[1] = -sin(theta)*(R + r*cos(phi1));
  670.         p3[2] = r*sin(phi1);
  671.  
  672.         n0[0] = cos(theta)*(cos(phi));
  673.         n0[1] = -sin(theta)*(cos(phi));
  674.         n0[2] = sin(phi);
  675.  
  676.         n1[0] = cos(theta1)*(cos(phi));
  677.         n1[1] = -sin(theta1)*(cos(phi));
  678.         n1[2] = sin(phi);
  679.  
  680.         n2[0] = cos(theta1)*(cos(phi1));
  681.         n2[1] = -sin(theta1)*(cos(phi1));
  682.         n2[2] = sin(phi1);
  683.  
  684.         n3[0] = cos(theta)*(cos(phi1));
  685.         n3[1] = -sin(theta)*(cos(phi1));
  686.         n3[2] = sin(phi1);
  687.  
  688.         m_xformpt(p0, p0, n0, n0);
  689.         m_xformpt(p1, p1, n1, n1);
  690.         m_xformpt(p2, p2, n2, n2);
  691.         m_xformpt(p3, p3, n3, n3);
  692.  
  693.         glBegin(type);
  694.         glNormal3dv(n3);
  695.         glVertex3dv(p3);
  696.         glNormal3dv(n2);
  697.         glVertex3dv(p2);
  698.         glNormal3dv(n1);
  699.         glVertex3dv(p1);
  700.         glNormal3dv(n0);
  701.         glVertex3dv(p0);
  702.         glEnd();
  703.     }
  704.     }
  705. }
  706.  
  707. /* octahedron data: The octahedron produced is centered 
  708.  * at the origin and has radius 1.0 
  709.  */
  710. static GLdouble odata[6][3] = {
  711.   {1.0, 0.0, 0.0},
  712.   {-1.0, 0.0, 0.0},
  713.   {0.0, 1.0, 0.0},
  714.   {0.0, -1.0, 0.0},
  715.   {0.0, 0.0, 1.0},
  716.   {0.0, 0.0, -1.0}
  717. };
  718.  
  719. static int ondex[8][3] = {
  720.     {0, 4, 2}, {1, 2, 4}, {0, 3, 4}, {1, 4, 3},
  721.     {0, 2, 5}, {1, 5, 2}, {0, 5, 3}, {1, 3, 5}
  722. };
  723.  
  724. /* tetrahedron data: */
  725.  
  726. #define T    1.73205080756887729
  727.  
  728. static GLdouble tdata[4][3] = {
  729.     {T, T, T}, {T, -T, -T}, {-T, T, -T}, {-T, -T, T}
  730. };
  731.  
  732. static int tndex[4][3] = {
  733.     {0, 1, 3}, {2, 1, 0}, {3, 2, 0}, {1, 2, 3}
  734. };
  735.  
  736. /* icosahedron data: These numbers are rigged to 
  737.  * make an icosahedron of radius 1.0 
  738.  */
  739.  
  740. #define X .525731112119133606
  741. #define Z .850650808352039932
  742.  
  743. static GLdouble idata[12][3] = {
  744.   {-X, 0.0, Z},
  745.   {X, 0.0, Z},
  746.   {-X, 0.0, -Z},
  747.   {X, 0.0, -Z},
  748.   {0.0, Z, X},
  749.   {0.0, Z, -X},
  750.   {0.0, -Z, X},
  751.   {0.0, -Z, -X},
  752.   {Z, X, 0.0},
  753.   {-Z, X, 0.0},
  754.   {Z, -X, 0.0},
  755.   {-Z, -X, 0.0},
  756. };
  757.  
  758. static int iindex[20][3] = {
  759.     {0, 4, 1},    {0, 9, 4},
  760.     {9, 5, 4},    {4, 5, 8},
  761.     {4, 8, 1},    {8, 10, 1},
  762.     {8, 3, 10},    {5, 3, 8},
  763.     {5, 2, 3},    {2, 7, 3},
  764.     {7, 10, 3},    {7, 6, 10},
  765.     {7, 11, 6},    {11, 0, 6},
  766.     {0, 1, 6},    {6, 1, 10},
  767.     {9, 0, 11},    {9, 11, 2},
  768.     {9, 2, 5},    {7, 2, 11},
  769. };
  770.  
  771. /* icosahedron:
  772.  *
  773.  * Draws an icosahedron with center at p0 having the
  774.  * given radius.
  775.  */
  776.  
  777. static void icosahedron(GLdouble p0[3], GLdouble radius, GLenum shadeType)
  778. {
  779.     int i;
  780.  
  781.     for(i = 0; i < 20; i++)
  782.     drawtriangle(i, 0, 1, p0, radius, shadeType, 0);
  783. }
  784.  
  785. /* octahedron:
  786.  *
  787.  * Draws an octahedron with center at p0 having the
  788.  * given radius.
  789.  */
  790. static void octahedron(GLdouble p0[3], GLdouble radius, GLenum shadeType)
  791. {
  792.     int i;
  793.  
  794.     for(i = 0; i < 8; i++)
  795.     drawtriangle(i, 1, 1, p0, radius, shadeType, 0);
  796. }
  797.  
  798. /* tetrahedron:
  799.  *
  800.  * Draws an tetrahedron with center at p0 having the
  801.  * given radius.
  802.  */
  803.  
  804. static void tetrahedron(GLdouble p0[3], GLdouble radius, GLenum shadeType)
  805. {
  806.     int i;
  807.  
  808.     for(i = 0; i < 4; i++)
  809.     drawtriangle(i, 2, 1, p0, radius, shadeType, 0);
  810. }
  811.  
  812. static void subdivide(int depth, GLdouble *v0, GLdouble *v1, GLdouble *v2,
  813.     GLdouble p0[3], GLdouble radius, GLenum shadeType, int avnormal)
  814. {
  815.     GLdouble w0[3], w1[3], w2[3];
  816.     GLdouble l;
  817.     int i, j, k, n;
  818.  
  819.     for(i = 0; i < depth; i++)
  820.     for(j = 0; i + j < depth; j++) {
  821.         k = depth - i - j;
  822.         for(n = 0; n < 3; n++) {
  823.         w0[n] = (i*v0[n] + j*v1[n] + k*v2[n])/depth;
  824.         w1[n] = ((i+1)*v0[n] + j*v1[n] +(k-1)*v2[n])/depth;
  825.         w2[n] = (i*v0[n] +(j+1)*v1[n] +(k-1)*v2[n])/depth;
  826.         }
  827.         l = sqrt(w0[0]*w0[0] + w0[1]*w0[1] + w0[2]*w0[2]);
  828.         w0[0] /= l; w0[1] /= l; w0[2] /= l;
  829.         l = sqrt(w1[0]*w1[0] + w1[1]*w1[1] + w1[2]*w1[2]);
  830.         w1[0] /= l; w1[1] /= l; w1[2] /= l;
  831.         l = sqrt(w2[0]*w2[0] + w2[1]*w2[1] + w2[2]*w2[2]);
  832.         w2[0] /= l; w2[1] /= l; w2[2] /= l;
  833.         recorditem(w1, w0, w2, p0, radius, shadeType, avnormal);
  834.     }
  835.     for(i = 0; i < depth-1; i++)
  836.     for(j = 0; i + j < depth-1; j++) {
  837.         k = depth - i - j;
  838.         for(n = 0; n < 3; n++) {
  839.         w0[n] = ((i+1)*v0[n] +(j+1)*v1[n] +(k-2)*v2[n])/depth;
  840.         w1[n] = ((i+1)*v0[n] + j*v1[n] +(k-1)*v2[n])/depth;
  841.         w2[n] = (i*v0[n] +(j+1)*v1[n] +(k-1)*v2[n])/depth;
  842.         }
  843.         l = sqrt(w0[0]*w0[0] + w0[1]*w0[1] + w0[2]*w0[2]);
  844.         w0[0] /= l; w0[1] /= l; w0[2] /= l;
  845.         l = sqrt(w1[0]*w1[0] + w1[1]*w1[1] + w1[2]*w1[2]);
  846.         w1[0] /= l; w1[1] /= l; w1[2] /= l;
  847.         l = sqrt(w2[0]*w2[0] + w2[1]*w2[1] + w2[2]*w2[2]);
  848.         w2[0] /= l; w2[1] /= l; w2[2] /= l;
  849.         recorditem(w0, w1, w2, p0, radius, shadeType, avnormal);
  850.     }
  851. }
  852.  
  853. static void drawtriangle(int i, int geomType, int depth,
  854.     GLdouble p0[3], GLdouble radius, GLenum shadeType, int avnormal)
  855. {
  856.     GLdouble *x0, *x1, *x2;
  857.  
  858.     switch(geomType) {
  859.     case 0:    /* icosahedron */
  860.         x0 = &idata[iindex[i][0]][0];
  861.         x1 = &idata[iindex[i][1]][0];
  862.         x2 = &idata[iindex[i][2]][0];
  863.         break;
  864.     case 1: /* octahedron */
  865.         x0 = &odata[ondex[i][0]][0];
  866.         x1 = &odata[ondex[i][1]][0];
  867.         x2 = &odata[ondex[i][2]][0];
  868.         break;
  869.     case 2: /* tetrahedron */
  870.         x0 = &tdata[tndex[i][0]][0];
  871.         x1 = &tdata[tndex[i][1]][0];
  872.         x2 = &tdata[tndex[i][2]][0];
  873.         break;
  874.     }
  875.     subdivide(depth, x0, x1, x2, p0, radius, shadeType, avnormal);
  876. }
  877.  
  878. static void recorditem(GLdouble *n1, GLdouble *n2, GLdouble *n3,
  879.     GLdouble center[3], GLdouble radius, GLenum shadeType, int avnormal)
  880. {
  881.     GLdouble p1[3], p2[3], p3[3], q0[3], q1[3], n11[3], n22[3], n33[3];
  882.     int    i;
  883.  
  884.     for(i = 0; i < 3; i++)
  885.     {
  886.         p1[i] = n1[i]*radius + center[i];
  887.         p2[i] = n2[i]*radius + center[i];
  888.         p3[i] = n3[i]*radius + center[i];
  889.     }
  890.  
  891.     if(avnormal == 0)
  892.     {
  893.         diff3(p1, p2, q0);
  894.         diff3(p2, p3, q1);
  895.         crossprod(q0, q1, q1);
  896.         normalize(q1);
  897.         m_xformpt(p1, p1, q1, n11);
  898.         m_xformptonly(p2, p2);
  899.         m_xformptonly(p3, p3);
  900.     
  901.         glBegin(shadeType);
  902.         glNormal3dv(n11);
  903.         glVertex3dv(p1);
  904.         glVertex3dv(p2);
  905.         glVertex3dv(p3);
  906.         glEnd();
  907.         
  908.         return;
  909.     }
  910.  
  911.     m_xformpt(p1, p1, n1, n11);
  912.     m_xformpt(p2, p2, n2, n22);
  913.     m_xformpt(p3, p3, n3, n33);
  914.  
  915.     glBegin(shadeType);
  916.     glNormal3dv(n11);
  917.     glVertex3dv(p1);
  918.     glNormal3dv(n22);
  919.     glVertex3dv(p2);
  920.     glNormal3dv(n33);
  921.     glVertex3dv(p3);
  922.     glEnd();
  923. }
  924.  
  925. static GLdouble dodec[20][3];
  926.  
  927. static void initdodec()
  928. {
  929.     GLdouble alpha, beta;
  930.  
  931.     alpha = sqrt(2.0/(3.0 + sqrt(5.0)));
  932.     beta = 1.0 + sqrt(6.0/(3.0 + sqrt(5.0)) - 2.0 + 2.0*sqrt(2.0/(3.0 + sqrt(5.0))));
  933.     
  934.     dodec[0][0] = -alpha; dodec[0][1] = 0; dodec[0][2] = beta;
  935.     dodec[1][0] = alpha; dodec[1][1] = 0; dodec[1][2] = beta;
  936.     dodec[2][0] = -1; dodec[2][1] = -1; dodec[2][2] = -1;
  937.     dodec[3][0] = -1; dodec[3][1] = -1; dodec[3][2] = 1;
  938.     dodec[4][0] = -1; dodec[4][1] = 1; dodec[4][2] = -1;
  939.     dodec[5][0] = -1; dodec[5][1] = 1; dodec[5][2] = 1;
  940.     dodec[6][0] = 1; dodec[6][1] = -1; dodec[6][2] = -1;
  941.     dodec[7][0] = 1; dodec[7][1] = -1; dodec[7][2] = 1;
  942.     dodec[8][0] = 1; dodec[8][1] = 1; dodec[8][2] = -1;
  943.     dodec[9][0] = 1; dodec[9][1] = 1; dodec[9][2] = 1;
  944.     dodec[10][0] = beta; dodec[10][1] = alpha; dodec[10][2] = 0;
  945.     dodec[11][0] = beta; dodec[11][1] = -alpha; dodec[11][2] = 0;
  946.     dodec[12][0] = -beta; dodec[12][1] = alpha; dodec[12][2] = 0;
  947.     dodec[13][0] = -beta; dodec[13][1] = -alpha; dodec[13][2] = 0;
  948.     dodec[14][0] = -alpha; dodec[14][1] = 0; dodec[14][2] = -beta;
  949.     dodec[15][0] = alpha; dodec[15][1] = 0; dodec[15][2] = -beta;
  950.     dodec[16][0] = 0; dodec[16][1] = beta; dodec[16][2] = alpha;
  951.     dodec[17][0] = 0; dodec[17][1] = beta; dodec[17][2] = -alpha;
  952.     dodec[18][0] = 0; dodec[18][1] = -beta; dodec[18][2] = alpha;
  953.     dodec[19][0] = 0; dodec[19][1] = -beta; dodec[19][2] = -alpha;
  954. }
  955.  
  956. /* dodecahedron:
  957.  *
  958.  * Draws an dodecahedron with center at 0.0. The radius
  959.  * is sqrt(3).
  960.  */
  961. static void dodecahedron(GLdouble center[3], GLdouble sc, GLenum type)
  962. {
  963.     static int inited = 0;
  964.  
  965.     if(inited == 0)
  966.     {
  967.         inited = 1;
  968.         initdodec();
  969.     }
  970.     
  971.     m_pushmatrix();
  972.     m_translate(center[0], center[1], center[2]);
  973.     m_scale(sc, sc, sc);
  974.     
  975.     pentagon(0, 1, 9, 16, 5, type);
  976.     pentagon(1, 0, 3, 18, 7, type);
  977.     pentagon(1, 7, 11, 10, 9, type);
  978.     pentagon(11, 7, 18, 19, 6, type);
  979.     pentagon(8, 17, 16, 9, 10, type);
  980.     pentagon(2, 14, 15, 6, 19, type);
  981.     pentagon(2, 13, 12, 4, 14, type);
  982.     pentagon(2, 19, 18, 3, 13, type);
  983.     pentagon(3, 0, 5, 12, 13, type);
  984.     pentagon(6, 15, 8, 10, 11, type);
  985.     pentagon(4, 17, 8, 15, 14, type);
  986.     pentagon(4, 12, 5, 16, 17, type);
  987.     
  988.     m_popmatrix();
  989. }
  990.  
  991. static void pentagon(int a, int b, int c, int d, int e, GLenum shadeType)
  992. {
  993.     GLdouble n0[3], d1[3], d2[3], d3[3], d4[3], d5[3], nout[3];
  994.  
  995.     diff3(&dodec[a][0], &dodec[b][0], d1);
  996.     diff3(&dodec[b][0], &dodec[c][0], d2);
  997.     crossprod(d1, d2, n0);
  998.     normalize(n0);
  999.     m_xformpt(&dodec[a][0], d1, n0, nout);
  1000.     m_xformptonly(&dodec[b][0], d2);
  1001.     m_xformptonly(&dodec[c][0], d3);
  1002.     m_xformptonly(&dodec[d][0], d4);
  1003.     m_xformptonly(&dodec[e][0], d5);
  1004.  
  1005.     glBegin(shadeType);
  1006.     glNormal3dv(nout);
  1007.     glVertex3dv(d1);
  1008.     glVertex3dv(d2);
  1009.     glVertex3dv(d3);
  1010.     glVertex3dv(d4);
  1011.     glVertex3dv(d5);
  1012.     glEnd();
  1013. }
  1014.  
  1015. /*    linked lists--display lists for each different 
  1016.  *    type of geometric objects.  The linked list is 
  1017.  *    searched, until an object of the requested
  1018.  *    size is found.  If no geometric object of that size
  1019.  *    has been previously made, a new one is created.
  1020.  */
  1021. static GLuint findList(int lindex, GLdouble *paramArray, int size) 
  1022. {
  1023.     MODELPTR endList;
  1024.     int found = 0;
  1025.  
  1026.     endList = lists[lindex];
  1027.     while(endList != NULL)
  1028.     {
  1029.         if(compareParams(endList->params, paramArray, size)) return(endList->list);
  1030.             
  1031.         endList = endList->ptr;
  1032.     }
  1033.     /*  if not found, return 0 and calling routine should
  1034.     *  make a new list    
  1035.     */
  1036.     return(0);
  1037. }
  1038.  
  1039. static int compareParams(GLdouble *oneArray, GLdouble *twoArray, int size) 
  1040. {
  1041.     int i;
  1042.     int matches = 1;
  1043.  
  1044.     for(i = 0;(i < size) && matches; i++)
  1045.     {
  1046.         if(*oneArray++ != *twoArray++) matches = 0;
  1047.     }
  1048.     
  1049.     return(matches);
  1050. }
  1051.  
  1052. static GLuint makeModelPtr(int lindex, int list, GLdouble *sizeArray, int count)
  1053. {
  1054.     MODELPTR newModel;
  1055.  
  1056.     newModel = (MODELPTR) malloc(sizeof(MODEL));
  1057.     
  1058.     if(list < 1)
  1059.         newModel->list = glGenLists(1);
  1060.     else
  1061.         newModel->list = list;
  1062.         
  1063.     newModel->numParam = count;
  1064.     newModel->params = sizeArray;
  1065.     newModel->ptr = lists[lindex];
  1066.     lists[lindex] = newModel;
  1067.  
  1068.     return(newModel->list);
  1069. }
  1070.